home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / ed.xmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-25  |  15.5 KB  |  636 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/ed.xmap.c,v 3.1 1991/07/15 19:37:24 christos Exp $ */
  2. /*
  3.  * ed.xmap.c: This module contains the procedures for maintaining
  4.  *          the extended-key map.
  5.  *
  6.  *           An extended-key (Xkey) is a sequence of keystrokes
  7.  *          introduced with an sequence introducer and consisting
  8.  *          of an arbitrary number of characters.  This module maintains
  9.  *          a map (the Xmap) to convert these extended-key sequences
  10.  *           into input strings or editor functions. It contains the
  11.  *          following externally visible functions.
  12.  *
  13.  *        int GetXkey(ch,code);
  14.  *        Char *ch;
  15.  *        Char **code;
  16.  *
  17.  *          Looks up *ch in map and then reads characters until a
  18.  *          complete match is found or a mismatch occurs.  Returns 1
  19.  *          for command and 0 for a string. Returns NULL in code for
  20.  *          no match and 0 as value.  The last character read is returned
  21.  *          in *ch.
  22.  *
  23.  *        void AddXkey(Xkey, code);
  24.  *        Char *Xkey;
  25.  *        Char * code;
  26.  *
  27.  *        void AddXkeyCmd(Xkey, CmdCode);
  28.  *        Char *Xkey;
  29.  *        Char CmdCode;
  30.  *
  31.  *          Adds Xkey to the Xmap and associates the code with it.  If
  32.  *          Xkey is already is in Xmap, the new code is applied to the
  33.  *          existing Xkey.
  34.  *
  35.  *            int DeleteXkey(Xkey);
  36.  *            Char *Xkey;
  37.  *
  38.  *          Delete the Xkey and all longer Xkeys staring with Xkey, if
  39.  *          they exists.
  40.  *
  41.  *          Warning:
  42.  *        If Xkey is a substring of some other Xkeys, then the longer
  43.  *        Xkeys are lost!!  That is, if the Xkeys "abcd" and "abcef"
  44.  *        are in Xmap, adding the key "abc" will cause the first two
  45.  *        definitions to be lost.
  46.  *
  47.  *        void ResetXmap();
  48.  *
  49.  *          Removes all entries from Xmap and resets the defaults.
  50.  *
  51.  *        void PrintXkey(Xkey);
  52.  *        Char *Xkey;
  53.  *
  54.  *          Prints all extended keys prefixed by Xkey and their associated
  55.  *          commands.
  56.  *
  57.  *          Restrictions:
  58.  *          -------------
  59.  *            1) It is not possible to have one Xkey that is a
  60.  *           substring of another.
  61.  */
  62. /*-
  63.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  64.  * All rights reserved.
  65.  *
  66.  * Redistribution and use in source and binary forms, with or without
  67.  * modification, are permitted provided that the following conditions
  68.  * are met:
  69.  * 1. Redistributions of source code must retain the above copyright
  70.  *    notice, this list of conditions and the following disclaimer.
  71.  * 2. Redistributions in binary form must reproduce the above copyright
  72.  *    notice, this list of conditions and the following disclaimer in the
  73.  *    documentation and/or other materials provided with the distribution.
  74.  * 3. All advertising materials mentioning features or use of this software
  75.  *    must display the following acknowledgement:
  76.  *    This product includes software developed by the University of
  77.  *    California, Berkeley and its contributors.
  78.  * 4. Neither the name of the University nor the names of its contributors
  79.  *    may be used to endorse or promote products derived from this software
  80.  *    without specific prior written permission.
  81.  *
  82.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  83.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  84.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  85.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  86.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  87.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  88.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  89.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  90.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  91.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  92.  * SUCH DAMAGE.
  93.  */
  94. #include "config.h"
  95. RCSID("$Id: ed.xmap.c,v 3.1 1991/07/15 19:37:24 christos Exp $")
  96.  
  97. #include "sh.h"
  98. #include "ed.h"
  99. #include "ed.defns.h"
  100.  
  101. #ifndef NULL
  102. #define NULL 0
  103. #endif
  104.  
  105. /* Internal Data types and declarations */
  106.  
  107. /* The Nodes of the Xmap.  The Xmap is a linked list of these node
  108.  * elements
  109.  */
  110. typedef struct Xmapnode {
  111.     Char    ch;            /* single character of Xkey */
  112.     Char   *code;        /* command code or pointer to string, if this
  113.                  * is a leaf */
  114.     struct Xmapnode *next;    /* ptr to next char of this Xkey */
  115.     struct Xmapnode *sibling;    /* ptr to another Xkey with same prefix */
  116. }       XmapNode;
  117.  
  118. static XmapNode *Xmap = NULL;    /* the current Xmap */
  119.  
  120. static Char CurCode;
  121. static XmapNode CurCmd = {0, &CurCode, NULL, NULL};
  122.  
  123. /* Some declarations of procedures */
  124. static    int            TraverseMap    __P((XmapNode *, Char *, Char **));
  125. static    int            TryNode    __P((XmapNode *, Char *, Char *, int));
  126. static    XmapNode    *GetFreeNode    __P((int));
  127. static    void         PutFreeNode    __P((XmapNode *));
  128. static    int         TryDeleteNode    __P((XmapNode **, Char *));
  129.  
  130.  
  131. /* ResetXmap():
  132.  *    Takes all nodes on Xmap and puts them on free list.  Then
  133.  *    initializes Xmap with arrow keys
  134.  */
  135. void
  136. ResetXmap(vi)
  137.     int     vi;
  138. {
  139.     static Char strA[] = {033, '[', 'A', '\0'};
  140.     static Char strB[] = {033, '[', 'B', '\0'};
  141.     static Char strC[] = {033, '[', 'C', '\0'};
  142.     static Char strD[] = {033, '[', 'D', '\0'};
  143.     static Char stOA[] = {033, 'O', 'A', '\0'};
  144.     static Char stOB[] = {033, 'O', 'B', '\0'};
  145.     static Char stOC[] = {033, 'O', 'C', '\0'};
  146.     static Char stOD[] = {033, 'O', 'D', '\0'};
  147.  
  148.     PutFreeNode(Xmap);
  149.     Xmap = NULL;
  150.     AddXkeyCmd(strA, F_UP_HIST);
  151.     AddXkeyCmd(strB, F_DOWN_HIST);
  152.     AddXkeyCmd(strC, F_CHARFWD);
  153.     AddXkeyCmd(strD, F_CHARBACK);
  154.     AddXkeyCmd(stOA, F_UP_HIST);
  155.     AddXkeyCmd(stOB, F_DOWN_HIST);
  156.     AddXkeyCmd(stOC, F_CHARFWD);
  157.     AddXkeyCmd(stOD, F_CHARBACK);
  158.     if (vi) {
  159.     AddXkeyCmd(&strA[1], F_UP_HIST);
  160.     AddXkeyCmd(&strB[1], F_DOWN_HIST);
  161.     AddXkeyCmd(&strC[1], F_CHARFWD);
  162.     AddXkeyCmd(&strD[1], F_CHARBACK);
  163.     AddXkeyCmd(&stOA[1], F_UP_HIST);
  164.     AddXkeyCmd(&stOB[1], F_DOWN_HIST);
  165.     AddXkeyCmd(&stOC[1], F_CHARFWD);
  166.     AddXkeyCmd(&stOD[1], F_CHARBACK);
  167.     }
  168.     return;
  169. }
  170.  
  171.  
  172. /* GetXkey():
  173.  *    Calls the recursive function with entry point Xmap
  174.  */
  175. int
  176. GetXkey(ch, code)
  177.     Char   *ch;
  178.     Char  **code;
  179. {
  180.     return (TraverseMap(Xmap, ch, code));
  181. }
  182.  
  183. /* TraverseMap():
  184.  *    recursively traverses node in tree until match or mismatch is
  185.  *     found.  May read in more characters.
  186.  */
  187. static int
  188. TraverseMap(ptr, ch, code)
  189.     XmapNode *ptr;
  190.     Char   *ch;
  191.     Char  **code;
  192. {
  193.     Char    tch;
  194.  
  195.     if (ptr->ch == *ch) {
  196.     /* match found */
  197.     if (ptr->next) {
  198.         if (ptr->next != &CurCmd) {
  199.         /* Xkey not complete so get next char */
  200.         if (GetNextChar(&tch) != 1) {    /* if EOF or error */
  201.             *ch = 0;
  202.             CurCmd.code[0] = F_SEND_EOF;
  203.             *code = CurCmd.code;
  204.             return 1;    /* PWP: Pretend we just read an end-of-file */
  205.         }
  206.         *ch = tch;
  207.         return (TraverseMap(ptr->next, ch, code));
  208.         }
  209.         else {
  210.         CurCmd.code[0] = (Char) ptr->code;
  211.         *code = CurCmd.code;
  212.         return 1;
  213.         }
  214.     }
  215.     else {
  216.         /* next is null so this is leaf node and a string */
  217.         *ch = 0;
  218.         *code = ptr->code;
  219.         return 0;
  220.     }
  221.     }
  222.     else {
  223.     /* no match found here */
  224.     if (ptr->sibling) {
  225.         /* try next sibling */
  226.         return (TraverseMap(ptr->sibling, ch, code));
  227.     }
  228.     else {
  229.         /* no next sibling -- mismatch */
  230.         *code = NULL;
  231.         return 0;
  232.     }
  233.     }
  234. }
  235.  
  236. void
  237. AddXkey(Xkey, code)
  238.     Char   *Xkey;
  239.     Char   *code;
  240. {
  241.     if (Xkey[0] == '\0') {
  242.     xprintf("AddXkey: Null extended-key not allowed.\n");
  243.     return;
  244.     }
  245.  
  246.     if (Xmap == NULL)
  247.     /* tree is initially empty.  Set up new node to match Xkey[0] */
  248.     Xmap = GetFreeNode(Xkey[0]);    /* it is properly initialized */
  249.  
  250.     /* Now recurse through Xmap */
  251.     (void) TryNode(Xmap, Xkey, code, 1);    /* string */
  252.     return;
  253. }
  254.  
  255. void
  256. AddXkeyCmd(Xkey, CmdCode)
  257.     Char   *Xkey;
  258.     int    CmdCode;
  259. {
  260.     /* Gould does not like casts... */
  261.     unsigned int compiler_bug;
  262.  
  263.     if (Xkey[0] == '\0') {
  264.     xprintf("AddXkeyCmd: Null extended-key not allowed.\n");
  265.     return;
  266.     }
  267.     if (CmdCode == F_XKEY) {
  268.     xprintf("AddXkeyCmd: sequence-lead-in command not allowed\n");
  269.     return;
  270.     }
  271.  
  272.     if (Xmap == NULL)
  273.     /* tree is initially empty.  Set up new node to match Xkey[0] */
  274.     Xmap = GetFreeNode(Xkey[0]);    /* it is properly initialized */
  275.  
  276.     /* Now recurse through Xmap */
  277.     compiler_bug = (unsigned int) CmdCode;
  278.     (void) TryNode(Xmap, Xkey, (Char *) compiler_bug, 0);    /* command */
  279.     return;
  280. }
  281.  
  282.  
  283. static int
  284. TryNode(ptr, string, code, IsString)
  285.     XmapNode *ptr;
  286.     Char   *string;
  287.     Char   *code;
  288.     int     IsString;
  289. {
  290.     /*
  291.      * Find a node that matches *string or allocate a new one
  292.      */
  293.     if (ptr->ch != *string) {
  294.     XmapNode *xm;
  295.  
  296.     for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  297.         if (xm->sibling->ch == *string)
  298.         break;
  299.     if (xm->sibling == NULL)
  300.         xm->sibling = GetFreeNode(*string);    /* setup new node */
  301.     ptr = xm->sibling;
  302.     }
  303.  
  304.     if (*++string == '\0') {
  305.     /* we're there */
  306.     if (ptr->next != NULL && ptr->next != &CurCmd) {
  307.         PutFreeNode(ptr->next);    /* lose longer Xkeys with this prefix */
  308.         ptr->next = NULL;
  309.     }
  310.     if (ptr->next == NULL && ptr->code)
  311.         xfree((ptr_t) ptr->code);
  312.     if (IsString) {
  313.         ptr->next = NULL;
  314.         ptr->code = Strsave(code);
  315.     }
  316.     else {
  317.         ptr->next = &CurCmd;
  318.         ptr->code = code;
  319.     }
  320.     }
  321.     else {
  322.     /* still more chars to go */
  323.     /*
  324.      * christos: We need to allocate a new XmapNode also if the next
  325.      * XmapNode is the CurCmd, cause the previous XmapNode definition was
  326.      * only one char long!
  327.      */
  328.     if (ptr->next == NULL || ptr->next == &CurCmd)
  329.         ptr->next = GetFreeNode(*string);    /* setup new node */
  330.     (void) TryNode(ptr->next, string, code, IsString);
  331.     }
  332.     return (0);
  333. }
  334.  
  335. void
  336. ClearXkey(map, in)
  337.     KEYCMD *map;
  338.     Char   *in;
  339. {
  340.     if ((map[(unsigned char) *in] == F_XKEY) &&
  341.     ((map == CcKeyMap && CcAltMap[(unsigned char) *in] != F_XKEY) ||
  342.      (map == CcAltMap && CcKeyMap[(unsigned char) *in] != F_XKEY)))
  343.     (void) DeleteXkey(in);
  344. }
  345.  
  346. int
  347. DeleteXkey(Xkey)
  348.     Char   *Xkey;
  349. {
  350.     if (Xkey[0] == '\0') {
  351.     xprintf("DeleteXkey: Null extended-key not allowed.\n");
  352.     return (-1);
  353.     }
  354.  
  355.     if (Xmap == NULL)
  356.     return (0);
  357.  
  358.     (void) TryDeleteNode(&Xmap, Xkey);
  359.     return (0);
  360. }
  361.  
  362. static int
  363. TryDeleteNode(inptr, string)
  364.     XmapNode **inptr;
  365.     Char   *string;
  366. {
  367.     XmapNode *ptr;
  368.     XmapNode *prev_ptr = NULL;
  369.  
  370.     ptr = *inptr;
  371.     /*
  372.      * Find a node that matches *string or allocate a new one
  373.      */
  374.     if (ptr->ch != *string) {
  375.     XmapNode *xm;
  376.  
  377.     for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  378.         if (xm->sibling->ch == *string)
  379.         break;
  380.     if (xm->sibling == NULL)
  381.         return (0);
  382.     prev_ptr = xm;
  383.     ptr = xm->sibling;
  384.     }
  385.  
  386.     if (*++string == '\0') {
  387.     /* we're there */
  388.     if (prev_ptr == NULL)
  389.         *inptr = ptr->sibling;
  390.     else
  391.         prev_ptr->sibling = ptr->sibling;
  392.     ptr->sibling = NULL;
  393.     PutFreeNode(ptr);
  394.     return (1);
  395.     }
  396.     else if (ptr->next != NULL && TryDeleteNode(&ptr->next, string) == 1) {
  397.     if (ptr->next != NULL)
  398.         return (0);
  399.     if (prev_ptr == NULL)
  400.         *inptr = ptr->sibling;
  401.     else
  402.         prev_ptr->sibling = ptr->sibling;
  403.     ptr->sibling = NULL;
  404.     PutFreeNode(ptr);
  405.     return (1);
  406.     }
  407.     else {
  408.     return (0);
  409.     }
  410. }
  411.  
  412.  
  413.  
  414.  
  415.  
  416. /* PutFreeNode():
  417.  *    Puts a tree of nodes onto free list using free(3).
  418.  */
  419. static void
  420. PutFreeNode(ptr)
  421.     XmapNode *ptr;
  422. {
  423.     if (ptr == NULL)
  424.     return;
  425.  
  426.     if (ptr->next && ptr->next != &CurCmd)
  427.     PutFreeNode(ptr->next);
  428.     PutFreeNode(ptr->sibling);
  429.     if (ptr->next == NULL && ptr->code)
  430.     xfree((ptr_t) ptr->code);
  431.     xfree((ptr_t) ptr);
  432. }
  433.  
  434.  
  435. /* GetFreeNode():
  436.  *    Returns pointer to an XmapNode for ch.
  437.  */
  438. static XmapNode *
  439. GetFreeNode(ch)
  440.     int    ch;
  441. {
  442.     XmapNode *ptr;
  443.  
  444.     ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode));
  445.     ptr->ch = ch;
  446.     ptr->code = NULL;
  447.     ptr->next = NULL;
  448.     ptr->sibling = NULL;
  449.     return (ptr);
  450. }
  451.  
  452. /* Now The Print Routine */
  453. #define maxXkey 100        /* max length of a Xkey for print putposes */
  454. static Char printbuf[maxXkey];    /* buffer for printing */
  455.  
  456. static int Lookup();
  457. static int Enumerate();
  458. static int printOne();
  459. static int unparsech();
  460. extern unsigned char *unparsestring();
  461.  
  462. /* PrintXKey():
  463.  *    Print the binding associated with Xkey key.
  464.  *    Print entire Xmap if null
  465.  */
  466. void
  467. PrintXkey(key)
  468.     Char   *key;
  469. {
  470.     /* do nothing if Xmap is empty and null key specified */
  471.     if (Xmap == NULL && *key == 0)
  472.     return;
  473.  
  474.     printbuf[0] = '"';
  475.     if (Lookup(key, Xmap, 1) <= -1)
  476.     /* key is not bound */
  477.     xprintf("Unbound extended key \"%s\"\n", short2str(key));
  478.     return;
  479. }
  480.  
  481. /* Lookup():
  482.  *    look for the string starting at node ptr.
  483.  *    Print if last node
  484.  */
  485. static int
  486. Lookup(string, ptr, cnt)
  487.     int     cnt;
  488.     Char   *string;
  489.     XmapNode *ptr;
  490. {
  491.     int     ncnt;
  492.  
  493.     if (ptr == NULL)
  494.     return (-1);        /* cannot have null ptr */
  495.  
  496.     if (*string == 0) {
  497.     /* no more chars in string.  Enumerate from here. */
  498.     (void) Enumerate(ptr, cnt);
  499.     return (0);
  500.     }
  501.     else {
  502.     /* If match put this char into printbuf.  Recurse */
  503.     if (ptr->ch == *string) {
  504.         /* match found */
  505.         ncnt = unparsech(cnt, ptr->ch);
  506.         if (ptr->next && ptr->next != &CurCmd)
  507.         /* not yet at leaf */
  508.         return (Lookup(string + 1, ptr->next, ncnt + 1));
  509.         else {
  510.         /* next node is null  or &CurCmd so key should be complete */
  511.         if (string[1] == 0) {
  512.             printbuf[ncnt + 1] = '"';
  513.             printbuf[ncnt + 2] = '\0';
  514.             (void) printOne(printbuf, ptr->code, ptr->next == NULL);
  515.             return (0);
  516.         }
  517.         else
  518.             return (-1);/* mismatch -- string still has chars */
  519.         }
  520.     }
  521.     else {
  522.         /* no match found try sibling */
  523.         if (ptr->sibling)
  524.         return (Lookup(string, ptr->sibling, cnt));
  525.         else
  526.         return (-1);
  527.     }
  528.     }
  529. }
  530.  
  531. static int
  532. Enumerate(ptr, cnt)
  533.     int     cnt;
  534.     XmapNode *ptr;
  535. {
  536.     int     ncnt;
  537.  
  538.     if (cnt >= maxXkey - 5) {    /* buffer too small */
  539.     printbuf[++cnt] = '"';
  540.     printbuf[++cnt] = '\0';
  541.     xprintf("Some extended keys too long for internal print buffer");
  542.     xprintf(" \"%s...\"\n", short2str(printbuf));
  543.     return (0);
  544.     }
  545.  
  546.     if (ptr == NULL) {
  547. #ifdef DEBUG_EDIT
  548.     xprintf("Enumerate: BUG!! Null ptr passed\n!");
  549. #endif
  550.     return (-1);
  551.     }
  552.  
  553.     ncnt = unparsech(cnt, ptr->ch);    /* put this char at end of string */
  554.     if (ptr->next == NULL || ptr->next == &CurCmd) {
  555.     /* print this Xkey and function */
  556.     printbuf[ncnt + 1] = '"';
  557.     printbuf[ncnt + 2] = '\0';
  558.     (void) printOne(printbuf, ptr->code, ptr->next == NULL);
  559.     }
  560.     else
  561.     (void) Enumerate(ptr->next, ncnt + 1);
  562.  
  563.     /* go to sibling if there is one */
  564.     if (ptr->sibling)
  565.     (void) Enumerate(ptr->sibling, cnt);
  566.     return (0);
  567. }
  568.  
  569.  
  570. /* PrintOne():
  571.  *    Print the specified key and its associated
  572.  *    function specified by code
  573.  */
  574. static int
  575. printOne(key, code, prstring)
  576.     Char   *key;
  577.     Char   *code;
  578.     int     prstring;
  579. {
  580.     struct KeyFuncs *fp;
  581.     unsigned char unparsbuf[200];
  582.     static char *fmt = "%-15s->  %s\n";
  583.  
  584.     if (code) {
  585.     if (prstring)
  586.         xprintf(fmt, short2str(key), unparsestring(code, unparsbuf));
  587.     else {
  588.         for (fp = FuncNames; fp->name; fp++) {
  589.         if ((int) code == fp->func)
  590.             xprintf(fmt, short2str(key), fp->name);
  591.         }
  592.     }
  593.     }
  594.     else
  595.     xprintf(fmt, short2str(key), "no input");
  596.     return (0);
  597. }
  598.  
  599. static int
  600. unparsech(cnt, ch)
  601.     int     cnt;
  602.     Char    ch;
  603. {
  604.     if (ch == 0) {
  605.     printbuf[cnt++] = '^';
  606.     printbuf[cnt] = '@';
  607.     return cnt;
  608.     }
  609.  
  610.     if (Iscntrl(ch)) {
  611.     printbuf[cnt++] = '^';
  612.     if (ch == '\177')
  613.         printbuf[cnt] = '?';
  614.     else
  615.         printbuf[cnt] = ch | 0100;
  616.     }
  617.     else if (ch == '^') {
  618.     printbuf[cnt++] = '\\';
  619.     printbuf[cnt] = '^';
  620.     }
  621.     else if (ch == '\\') {
  622.     printbuf[cnt++] = '\\';
  623.     printbuf[cnt] = '\\';
  624.     }
  625.     else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
  626.     printbuf[cnt] = ch;
  627.     }
  628.     else {
  629.     printbuf[cnt++] = '\\';
  630.     printbuf[cnt++] = ((ch >> 6) & 7) + '0';
  631.     printbuf[cnt++] = ((ch >> 3) & 7) + '0';
  632.     printbuf[cnt] = (ch & 7) + '0';
  633.     }
  634.     return cnt;
  635. }
  636.